package com.dbflow5.processor.definition.behavior;

import com.dbflow5.StringUtils;
import com.dbflow5.annotation.ModelCacheField;
import com.dbflow5.annotation.MultiCacheField;
import com.dbflow5.processor.ProcessorManager;
import com.dbflow5.processor.utils.ProcessorUtils;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;

public class Behaviors{
    /**
     * Defines how a class is named, db it belongs to, and other loading behaviors.
     */
    public static class AssociationalBehavior {
        /**
         * The name of this object in the database. Default is the class name.
         */
        public String name;
        /**
         * The class of the database this corresponds to.
         */
        public TypeName databaseTypeName;
        /**
         * When true, all public, package-private , non-static, and non-final fields of the reference class are considered as [com.dbflow5.annotation.Column] .
         * The only required annotated field becomes The [PrimaryKey]
         * or [PrimaryKey.autoincrement].
         */
        public boolean allFields;

        public AssociationalBehavior(String name, TypeName databaseTypeName, boolean allFields) {
            this.name = name;
            this.databaseTypeName = databaseTypeName;
            this.allFields = allFields;
        }

        public void writeName(TypeSpec.Builder typeSpec) {
            typeSpec.addMethod(MethodSpec
                    .methodBuilder("getName")
                    .returns(TypeName.get(String.class))
                    .addAnnotation(Override.class)
                    .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                    .addStatement("return " + StringUtils.quote(name))
                    .build());
        }
    }


    /**
     * Defines how a Cursor gets loaded from the DB.
     */
    public static class CursorHandlingBehavior {
        public boolean orderedCursorLookup;
        public boolean assignDefaultValuesFromCursor = true;

        public CursorHandlingBehavior(boolean orderedCursorLookup, boolean assignDefaultValuesFromCursor) {
            this.orderedCursorLookup = orderedCursorLookup;
            this.assignDefaultValuesFromCursor = assignDefaultValuesFromCursor;
        }
    }

    /**
     * Describes caching behavior of a [TableDefinition].
     */
    public static class CachingBehavior {
        public boolean cachingEnabled;
        public int customCacheSize;
        public String customCacheFieldName;
        public String customMultiCacheFieldName;

        public CachingBehavior(boolean cachingEnabled, int customCacheSize, String customCacheFieldName, String customMultiCacheFieldName) {
            this.cachingEnabled = cachingEnabled;
            this.customCacheSize = customCacheSize;
            this.customCacheFieldName = customCacheFieldName;
            this.customMultiCacheFieldName = customMultiCacheFieldName;
        }

        public void clear() {
            customCacheFieldName = null;
            customMultiCacheFieldName = null;
        }

        /**
         * If applicable, we store the [customCacheFieldName] or [customMultiCacheFieldName] for reference.
         *
         * @param element element
         * @param typeElement typeElement
         * @param manager manager
         */
        public void evaluateElement(Element element, TypeElement typeElement, ProcessorManager manager) {
            if (element.getAnnotation(ModelCacheField.class) != null) {
                ProcessorUtils.ensureVisibleStatic(element, typeElement, "ModelCacheField");
                if (!StringUtils.isNullOrEmpty(customCacheFieldName)) {
                    manager.logError("ModelCacheField can only be declared once from: $typeElement");
                } else {
                    customCacheFieldName = element.getSimpleName().toString();
                }
            } else if (element.getAnnotation(MultiCacheField.class) != null) {
                ProcessorUtils.ensureVisibleStatic(element, typeElement, "MultiCacheField");
                if (!StringUtils.isNullOrEmpty(customMultiCacheFieldName)) {
                    manager.logError("MultiCacheField can only be declared once from: $typeElement");
                } else {
                    customMultiCacheFieldName = element.getSimpleName().toString();
                }
            }
        }
    }
}

